using System;
using System.Net.Sockets;
using System.Text;
using System.Net;

using Coding4Fun.Maelstrom.Hardware.Diagnostics;

namespace Coding4Fun.Maelstrom.Hardware.WebServer
{
    /// <summary>
    /// Holds information about a web request
    /// </summary>
    /// <remarks>
    /// Will expand as required, but stay simple until needed.
    /// </remarks>
    public class Request : IDisposable
    {
    	private Socket _client;
        const int ChunkSize = 1024;

    	internal Request(Socket client, char[] data)
        {
            _client = client;
            ProcessRequest(data);
        }

    	/// <summary>
    	/// Request method
    	/// </summary>
    	public string Method { get; private set; }

    	/// <summary>
    	/// URL of request
    	/// </summary>
    	public string Url { get; private set; }

    	/// <summary>
        /// Client IP address
        /// </summary>
        public IPAddress Client
        {
            get
            {
                var ip = _client.RemoteEndPoint as IPEndPoint;
                return ip != null ? ip.Address : null;
            }
        }

    	/// <summary>
    	/// Send a response back to the client
    	/// </summary>
    	/// <param name="response"></param>
    	/// <param name="type"></param>
    	public void SendResponse(string response, string type = "text/html")
        {
			var length = response.Length;
			int i = 0;
			SendHeader(length, type);

			var bytes = new byte[ChunkSize];
    	    while(i < length)
			{
				var amount = (length < i + ChunkSize) ? (length - i) : ChunkSize;

				if (amount != ChunkSize)
				{
					bytes = new byte[amount];
				}

				for (int j = 0; j < amount; j++)
				{
					bytes[j] = (byte) response[i + j];
				}
				
				_client.Send(bytes);//, bytes.Length, SocketFlags.Partial);
				//Logger.WriteLine(i);
				i += ChunkSize;
			}

			Logger.WriteLine("Response of " + length + " sent.");
        }

		/// <summary>
		/// Send a response back to the client
		/// </summary>
		/// <param name="response"></param>
		/// <param name="type"></param>
		public void SendResponse(byte[] response, string type = "text/html")
		{
			SendHeader(response.Length, type);
			_client.Send(response, response.Length, SocketFlags.None);

			Logger.WriteLine("Response of " + response.Length + " sent.");
		}

    	private void SendHeader(int length, string type)
    	{
			if (_client == null)
				return;

			var header = "HTTP/1.0 200 OK\r\nContent-Type: " + type + "; charset=utf-8\r\nContent-Length: " + length +
						 "\r\nConnection: close\r\n\r\n";

			_client.Send(Encoding.UTF8.GetBytes(header));
    	}

    	/// <summary>
        /// Process the request header
        /// </summary>
        /// <param name="data"></param>
        private void ProcessRequest(char[] data)
        {
            var content = new string(data);

			if (content == null)
				return;

            var firstLine = content.Substring(0, content.IndexOf('\n'));

            // Parse the first line of the request: "GET /path/ HTTP/1.1"
            var words = firstLine.Split(' ');
            Method = words[0];
            Url = words[1];
        }


        #region IDisposable Members

        public void Dispose()
        {
        	if (_client == null)
				return;

        	_client.Close();
        	_client = null;
        }

        #endregion
    }
}
